package com.repro.lib_base.bases.vm

import android.app.Application
import androidx.annotation.StringRes
import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.MutableLiveData
import com.future.retronet.RetroException
import com.repro.com.repro.lib_base.R
import com.repro.libtoast.ToastUtil
import kotlinx.coroutines.*
import java.net.SocketTimeoutException
import java.net.UnknownHostException

abstract class BaseViewModel : AndroidViewModel {
    /**
     * show hide loading 的监听
     */
    private var showLoadingLiveData: MutableLiveData<Boolean>? = null

    /**
     * toast监听
     */
    private var showToastLiveData: MutableLiveData<String>? = null


    constructor(application: Application) : super(application)

    fun getShowLoadingLiveData(): MutableLiveData<Boolean> {
        if (showLoadingLiveData == null) {
            showLoadingLiveData = MutableLiveData<Boolean>()
        }
        return showLoadingLiveData!!
    }

    fun getShowToastLiveData(): MutableLiveData<String> {
        if (showToastLiveData == null) {
            showToastLiveData = MutableLiveData<String>()
        }
        return showToastLiveData!!
    }

    private fun showToast(@StringRes resInt: Int) {
        ToastUtil.show(getApplication(), resInt)
    }

    private fun showToast(resInt: String?) {
        ToastUtil.show(getApplication(), resInt)
    }

    /**
     * 函数体 block
     */
    fun networkDefault(block: suspend CoroutineScope.() -> Unit) {
        GlobalScope.launch(Dispatchers.Main) {
            try {
                block.invoke(this)
            } catch (e: Exception) {
                e.printStackTrace()//执行异常捕获
                if (e is RetroException) {
                    if (e.code == -1) {
                        //code拦截
                        showToast(e.message)
                    }
                } else if (e is SocketTimeoutException) {
                    showToast(R.string.retro_socket_timeout_exception)
                } else if (e is UnknownHostException) {
                    showToast(R.string.retro_unknown_host_exception)
                } else {
                    showToast(e.message)
                }
            } finally {
                //最终可以不做任何处理
            }
        }
    }

    /**
     * 协程网络请求框架
     * @param isShowLoading 是否展示loading
     * @param cw callback CoroutineScopeWrap 一个方法对象
     *
     * retroNet(true) {
     *      //协成suspend挂起函数执行代码块
     *      doWork {
     *          //网络情况代码块
     *          val data = RetroNet.create(texts::class.java).randomList()
     *          getShowToastLiveData().value = data[0].avatar
     *          testData.value = data
     *      }
     *      doError{
     *          //错误处理提示TODO
     *      }
     *      doCompleter{
     *          //完成状态，网络已经彻底执行完毕
     *      }
     *  }
     *
     */
    @DelicateCoroutinesApi
    fun retroNet(isShowLoading: Boolean = false, cw: suspend CoroutineScopeWrap.() -> Unit) {
        GlobalScope.launch(Dispatchers.Main) {
            getShowLoadingLiveData().value = isShowLoading
            val block = CoroutineScopeWrap()//创建CoroutineScopeWrap对象
            try {
                cw.invoke(block)//将CoroutineScopeWrap丢retroNet方法
                block.doWork.invoke(this)//代码块
            } catch (e: Exception) {
                when (e) {
                    is RetroException -> {
                        if (e.code == -1) {//code拦截
                            showToast(e.message)
                        }
                        ToastUtil.showDebug(getApplication(), "code=${e.code} + message = ${e.message}")
                    }
                    is SocketTimeoutException -> {
                        showToast(R.string.retro_socket_timeout_exception)
                    }
                    is UnknownHostException -> {
                        showToast(R.string.retro_unknown_host_exception)
                    }
                    else -> {
                        e.printStackTrace()
                        block.doError.invoke(e)
                        ToastUtil.showDebug(getApplication(), e.message)
                    }
                }
            } finally {
                getShowLoadingLiveData().value = false
                block.doCompleter.invoke()
            }
        }
    }
}